import { computed } from 'vue';
import { forEachValueKey } from './utils';

/**
 * 再次封装mutations的某个type方法执行并传入state, payload
 * 目的是给store._mutations对象定义方法并加工执行方法
 * @param {*} store store实例
 * @param {*} mutations 用户配置的mutations对象
 */
export function createMutations(store, mutations) {
  //mutationFn -> 函数本体
  //mutationKey -> 方法名称
  forEachValueKey(mutations, (mutationFn, mutationKey) => {
    //开发者如果执行mutations定义的某个方法时，需要传入参数store, payload，底层需代理至store._mutations(payload)执行
    store._mutations[mutationKey] = (payload) => {
      mutationFn.apply(store, [store.state, payload]);
    };
  });
}

/**
 * 再次封装actions的某个type方法执行并传入store, payload
 * 目的是给store._actions对象定义方法并加工执行方法
 * @param {*} store store实例
 * @param {*} actions 用户配置的actions对象
 */
export function createActions(store, actions) {
  forEachValueKey(actions, (actionFn, actionKey) => {
    //定义_actions里的方法并执行传入参数
    store._actions[actionKey] = (payload) => {
      actionFn.apply(store, [store, payload]);
    };
  });
}

/**
 * 再次封装getters的某个type方法执行并传入state, getters
 * 目的是给store.getters对象设置访问代理根据依赖(getter)变化计算获取新的值
 * @param {*} store store实例
 * @param {*} getters 用户配置的getters对象
 */
export function createGetters(store, getters) {
  //初始化store.getters为空对象
  store.getters = {};

  forEachValueKey(getters, (getterFn, getterKey) => {
    //访问 store.getters.xxx 返回 getterFn函数执行后的结果
    Object.defineProperty(store.getters, getterKey, {
      //访问 store.getters.filteredTodos时返回执行结果
      get() {
        //只有依赖发生变更时才会重新计算获取新的值
        return computed(() => getterFn(store.state, store.getters)).value;
      }
    });
  });
}

/**
 * 再次封装给Store实例新增commit API方法供开发者使用
 * @param {*} store store实例
 * @param {*} commit 实例底下仍未绑定实例的方法
 */
export function createCommitFn(store, commit) {
  //给Store实例新增commit方法
  store.commit = function (type, payload) {
    commit.apply(store, [type, payload]);
  };
}

/**
 * 再次封装给Store实例新增dispatch API方法供开发者使用
 * @param {*} store store实例
 * @param {*} dispatch 实例底下仍未绑定实例的方法
 */
export function createDispatchFn(store, dispatch) {
  store.dispatch = function (type, payload) {
    dispatch.apply(store, [type, payload]);
  };
}
